/********************************************************************************
* @file    onewire.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2020-12-07
* @brief   可用于ws2812x等
ws2812x数据传输时间
T0H 0 码，高电平时间  220ns~380ns
T0L 0 码，低电平时间  580ns~1.6µs
T1H 1 码，高电平时间  580ns~1.6µs
T1L 1 码，低电平时间  220ns~420µs
RES 帧单位，低电平时间 >280µs 以上

对于ARM_M平台 @16M
1个NOP：(1/24000000)*1000*1000*1000==41.67ns
__NOP(); __NOP(); __NOP(); __NOP(); __NOP();      \
对于n76e003平台 @16M
1个nop      占用87ns
while(1)    占用194ns
函数调用     占用570ns

注：1.如果点亮白灯或混色造成灯光无改变，则需要检测供电是否充足，接外部电池则满足需求。
2. 如果多个灯光出现颜色不对，则先检测供电问题。
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "bsp_gpio.h"

#include "sys_api.h"
#include "os_api.h"

#include "onewire.h"
#include "ls_gpio.h"
#include "ls_syscfg.h"

/* Private Define ------------------------------------------------------------*/
#if 1
#define T0_BIT_SIGNAL(GPIOX, PIN)                     \
    GPIOX->ODSET=PIN;                                 \
    __NOP(); __NOP(); __NOP(); __NOP(); __NOP();      \
    GPIOX->ODCLR=PIN;                                 \
    __NOP(); __NOP(); __NOP(); __NOP(); __NOP();      \
    __NOP(); __NOP(); __NOP(); __NOP(); __NOP();      \

#define T1_BIT_SIGNAL(GPIOX, PIN)                     \
    GPIOX->ODSET=PIN;                                 \
    __NOP(); __NOP(); __NOP(); __NOP(); __NOP();      \
    __NOP(); __NOP(); __NOP(); __NOP(); __NOP();      \
    __NOP(); __NOP(); __NOP(); __NOP(); __NOP();      \
    __NOP(); __NOP(); __NOP(); __NOP(); __NOP();      \
    GPIOX->ODCLR=PIN;                                 \
    __NOP(); __NOP(); __NOP(); __NOP(); __NOP();      \

#define RESET_SIGNAL(GPIOX, PIN)                      \
    io_out(GPIOX, PIN, IO_LOW); \
    delay(500);                                       \

#endif
/* Private Function Prototypes -----------------------------------------------*/
#if LS_APP_LED_WS2812_DRIVEN_MODE
static void delay(uint16_t cnt)
{
    while (cnt--)
    {
        __NOP();
    }
}
#endif
void onewire_init(void)
{
#if LS_WS2812_CH0_EN
    io_set_clk(GPIO_APBx, LS_ONEWIRE_CH0_GPIO_CLK, true);
    io_set_out_mode(ONEWIRE_CH0_PORT, ONEWIRE_CH0_PIN, IO_OUT_PP);
    io_out(ONEWIRE_CH0_PORT, ONEWIRE_CH0_PIN, IO_LOW);
#endif
#if LS_WS2812_CH1_EN
    LS_ONEWIRE_CH1_GPIO_CLK_ENABLE();
    io_set_out_mode(ONEWIRE_CH1_PORT, ONEWIRE_CH1_PIN, IO_OUT_PP);
    io_out(ONEWIRE_CH1_PORT, ONEWIRE_CH1_PIN, IO_LOW);
#endif
#if LS_WS2812_CH2_EN
    LS_ONEWIRE_CH2_GPIO_CLK_ENABLE();
    io_set_out_mode(ONEWIRE_CH2_PORT, ONEWIRE_CH2_PIN, IO_OUT_PP);
    io_out(ONEWIRE_CH2_PORT, ONEWIRE_CH2_PIN, IO_LOW);
#endif
#if LS_WS2812_CH3_EN
    LS_ONEWIRE_CH3_GPIO_CLK_ENABLE();
    io_set_out_mode(ONEWIRE_CH3_PORT, ONEWIRE_CH3_PIN, IO_OUT_PP);
    io_out(ONEWIRE_CH3_PORT, ONEWIRE_CH3_PIN, IO_LOW);
#endif
}

void onewire_deinit(void)
{
#if LS_WS2812_CH0_EN
    io_deinit(ONEWIRE_CH0_PORT, ONEWIRE_CH0_PIN);
#endif
#if LS_WS2812_CH1_EN
    io_deinit(ONEWIRE_CH1_PORT, ONEWIRE_CH1_PIN);
#endif
#if LS_WS2812_CH2_EN
    io_deinit(ONEWIRE_CH2_PORT, ONEWIRE_CH2_PIN);
#endif
#if LS_WS2812_CH3_EN
    io_deinit(ONEWIRE_CH3_PORT, ONEWIRE_CH3_PIN);
#endif
}
bool flag = false;
void onewire_send_data(uint8_t ch, uint8_t *data, uint8_t len)
{
    if (ch == 0)
    {
#if LS_WS2812_CH0_EN
        if (flag)
        {
            return;
        }
        flag = true;
        uint32_t val = SysTick->CTRL;
        SysTick->CTRL &= ~0x00000003; // 禁用 SysTick 中断
        sys_disable_irq();
        RESET_SIGNAL(ONEWIRE_CH0_PORT, ONEWIRE_CH0_PIN);
        uint8_t temp = 0;
        for (uint8_t n = 0; n < LS_WS2812_CH0_NUM; n++)
        {
            for (uint8_t i = 0; i < len; i++)
            {
                temp = data[i];
                for (uint8_t j = 0; j < 8; j++)
                {
                    if (temp & 0x80)
                    {
                        T1_BIT_SIGNAL(ONEWIRE_CH0_PORT, ONEWIRE_CH0_PIN)
                    }
                    else
                    {
                        T0_BIT_SIGNAL(ONEWIRE_CH0_PORT, ONEWIRE_CH0_PIN);
                    }
                    temp <<= 1;
                }
            }
        }
        RESET_SIGNAL(ONEWIRE_CH0_PORT, ONEWIRE_CH0_PIN);
        SysTick->CTRL = val;
        sys_enable_irq();
        flag = false;
#endif
    }
}
